package sj;

import lombok.extern.slf4j.Slf4j;

import java.util.Random;

/**
 * 、活锁：活锁指的是任务或者执行者没有被阻塞，由于某些条件没有满足，导致一直重复尝试—失败—尝试—失败的过程。
 * 、不会死锁，因为并非 占有且等待，而会释放锁。
 * 、线程互相持有各自的锁，发现需要的锁都被对方持有，就会释放当前持有的锁；
 * 导致大家都在不停持锁，释放锁，但事情还没做。
 * 当然还是会存在转账成功的情景，不过效率低下。
 * 、线程较多的情况会导致部分线程始终无法获取到锁，导致活锁。
 */
@Slf4j
public class Account2_ReentrantLock_live {

    public static void main(String[] args) throws InterruptedException {
        Account a = new Account(200);
        Account b = new Account(300);

        Thread thread1 = new Thread(() -> {
            try {
                transfer(a, b, 100);
            } catch (InterruptedException e) {
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                transfer(b, a, 100);
            } catch (InterruptedException e) {
            }
        });

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();

        System.out.println("成功");
    }

    static void transfer(Account soure, Account target, int amt) throws InterruptedException {
        Boolean isContinue = true;
        while (isContinue) {
            Thread.sleep(new Random().nextInt(99));

            if (soure.getLock().tryLock()) { //非阻塞获取锁。--锁定转出账户
                log.info("{}已获取锁 time{}", soure.getLock(), System.currentTimeMillis());
                try {
                    if (target.getLock().tryLock()) { //-----锁定转入账户
                        log.info("{}已获取锁 time{}", target.getLock(), System.currentTimeMillis());
                        try {
                            if (soure.getBalance() > amt) {
                                log.info("开始转账操作");
                                soure.setBalance(soure.getBalance() - amt);
                                target.setBalance(target.getBalance() + amt);
                                log.info("结束转账操作 source{} target{}", soure.getBalance(), target.getBalance());
                                isContinue = false;
                            }
                        } finally {
                            log.info("{}释放锁 time{}", target.getLock(), System.currentTimeMillis());
                            target.getLock().unlock();
                        }
                    }
                } finally {
                    log.info("{}释放锁 time{}", soure.getLock(), System.currentTimeMillis());
                    soure.getLock().unlock();
                }
            }
        }
    }
}
